home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / icmp.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  7KB  |  276 lines

  1. /* Internet Control Message Protocol (ICMP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "iface.h"
  8. #include "ip.h"
  9. #include "icmp.h"
  10. #include "netuser.h"
  11.  
  12. struct mib_entry Icmp_mib[] = {
  13.     "",                     0,
  14.     "icmpInMsgs",           0,
  15.     "icmpInErrors",         0,
  16.     "icmpInDestUnreachs",   0,
  17.     "icmpInTimeExcds",      0,
  18.     "icmpInParmProbs",      0,
  19.     "icmpInSrcQuenchs",     0,
  20.     "icmpInRedirects",      0,
  21.     "icmpInEchos",          0,
  22.     "icmpInEchoReps",       0,
  23.     "icmpInTimestamps",     0,
  24.     "icmpInTimestampReps",  0,
  25.     "icmpInAddrMasks",      0,
  26.     "icmpInAddrMaskReps",   0,
  27.     "icmpOutMsgs",          0,
  28.     "icmpOutErrors",        0,
  29.     "icmpOutDestUnreachs",  0,
  30.     "icmpOutTimeExcds",     0,
  31.     "icmpOutParmProbs",     0,
  32.     "icmpOutSrcQuenchs",    0,
  33.     "icmpOutRedirects",     0,
  34.     "icmpOutEchos",         0,
  35.     "icmpOutEchoReps",      0,
  36.     "icmpOutTimestamps",    0,
  37.     "icmpOutTimestampReps", 0,
  38.     "icmpOutAddrMasks",     0,
  39.     "icmpOutAddrMaskReps",  0,
  40. };
  41.  
  42. /* Process an incoming ICMP packet */
  43. void
  44. icmp_input(iface,ip,bp,rxbroadcast)
  45. struct iface *iface;    /* Incoming interface (ignored) */
  46. struct ip *ip;          /* Pointer to decoded IP header structure */
  47. struct mbuf *bp;        /* Pointer to ICMP message */
  48. int rxbroadcast;
  49. {
  50.     struct icmplink *ipp;
  51.     struct mbuf *tbp;
  52.     struct icmp icmp;       /* ICMP header */
  53.     struct ip oip;          /* Offending datagram header */
  54.     int16 type;             /* Type of ICMP message */
  55.     int16 length;
  56.     int ok_trace;
  57.     char temp[40];
  58.  
  59.     icmpInMsgs++;
  60.     if(rxbroadcast){
  61.         /* Broadcast ICMP packets are to be IGNORED !! */
  62.         icmpInErrors++;
  63.         free_p(bp);
  64.         return;
  65.     }
  66.     length = ip->length - IPLEN - ip->optlen;
  67.     if(cksum(NULLHEADER,bp,length) != 0){
  68.         /* Bad ICMP checksum; discard */
  69.         icmpInErrors++;
  70.         free_p(bp);
  71.         return;
  72.     }
  73.     ntohicmp(&icmp,&bp);
  74.  
  75.     /* Process the message. Some messages are passed up to the protocol
  76.      * module for handling, others are handled here.
  77.      */
  78.     type = icmp.type;
  79.     
  80.     switch(uchar(type)){
  81.     case ICMP_TIME_EXCEED:  /* Time-to-live Exceeded */
  82.     case ICMP_DEST_UNREACH: /* Destination Unreachable */
  83.     case ICMP_QUENCH:       /* Source Quench */
  84.         switch(uchar(type)){
  85.         case ICMP_TIME_EXCEED:  /* Time-to-live Exceeded */
  86.             icmpInTimeExcds++;
  87.             break;
  88.         case ICMP_DEST_UNREACH: /* Destination Unreachable */
  89.             icmpInDestUnreachs++;
  90.             break;
  91.         case ICMP_QUENCH:       /* Source Quench */
  92.             icmpInSrcQuenchs++;
  93.             break;
  94.         }
  95.         ntohip(&oip,&bp);       /* Extract offending IP header */
  96.         if(Icmp_trace){
  97.             switch(uchar(type)){
  98.             case ICMP_TIME_EXCEED:
  99.                 ok_trace=1;
  100.                 sprintf(temp,"%s",
  101.                  smsg(Exceed,NEXCEED,(unsigned)uchar(icmp.code)));
  102.                 break;
  103.             case ICMP_DEST_UNREACH:
  104.                 ok_trace=1;
  105.                 sprintf(temp,"%s",
  106.                  smsg(Unreach,NUNREACH,(unsigned)uchar(icmp.code)));
  107.                 break;
  108.             default:
  109.                 ok_trace=0;
  110.                 sprintf(temp,"%u",uchar(icmp.code));
  111.                 break;
  112.             }
  113.            
  114.            if ((Icmp_trace==1) || (Icmp_trace==2 && ok_trace)){
  115.  
  116.              printf("ICMP from %s:",inet_ntoa(ip->source));
  117.              printf(" dest %s %s ",inet_ntoa(oip.dest),
  118.               smsg(Icmptypes,ICMP_TYPES,(unsigned)uchar(type)));
  119.              printf(" %s\n",temp);
  120.              
  121.           }
  122.         }
  123.         for(ipp = Icmplink;ipp->funct != NULL;ipp++)
  124.             if(ipp->proto == oip.protocol)
  125.                 break;
  126.         if(ipp->funct != NULL){
  127.             (*ipp->funct)(ip->source,oip.source,oip.dest,icmp.type,
  128.              icmp.code,&bp);
  129.         }
  130.         break;
  131.     case ICMP_ECHO:         /* Echo Request */
  132.         /* Change type to ECHO_REPLY, recompute checksum,
  133.          * and return datagram.
  134.          */
  135.         icmpInEchos++;
  136.         icmp.type = ICMP_ECHO_REPLY;
  137.         if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
  138.             free_p(bp);
  139.             return;
  140.         }
  141.         icmpOutEchoReps++;
  142.         ip_send(ip->dest,ip->source,ICMP_PTCL,ip->tos,0,tbp,length,0,0);
  143.         return;
  144.     case ICMP_REDIRECT:     /* Redirect */
  145.         icmpInRedirects++;
  146.         break;
  147.     case ICMP_PARAM_PROB:   /* Parameter Problem */
  148.         icmpInParmProbs++;
  149.         break;
  150.     case ICMP_ECHO_REPLY:   /* Echo Reply */
  151.         icmpInEchoReps++;
  152.         echo_proc(ip->source,ip->dest,&icmp,bp);
  153.         bp = NULLBUF;   /* so it won't get freed */
  154.         break;
  155.     case ICMP_TIMESTAMP:    /* Timestamp */
  156.         icmpInTimestamps++;
  157.         break;
  158.     case ICMP_TIME_REPLY:   /* Timestamp Reply */
  159.         icmpInTimestampReps++;
  160.         break;
  161.     case ICMP_INFO_RQST:    /* Information Request */
  162.         break;
  163.     case ICMP_INFO_REPLY:   /* Information Reply */
  164.         break;
  165.     }
  166.     free_p(bp);
  167. }
  168. /* Return an ICMP response to the sender of a datagram.
  169.  * Unlike most routines, the callER frees the mbuf.
  170.  */
  171. int
  172. icmp_output(ip,data,type,code,args)
  173. struct ip *ip;          /* Header of offending datagram */
  174. struct mbuf *data;      /* Data portion of datagram */
  175. char type,code;         /* Codes to send */
  176. union icmp_args *args;
  177. {
  178.     struct mbuf *bp = NULLBUF;
  179.     struct icmp icmp;       /* ICMP protocol header */
  180.     int16 dlen;             /* Length of data portion of offending pkt */
  181.     int16 length;           /* Total length of reply */
  182.  
  183.     if(ip == NULLIP)
  184.         return -1;
  185.     if(uchar(ip->protocol) == ICMP_PTCL){
  186.         /* Peek at type field of ICMP header to see if it's safe to
  187.          * return an ICMP message
  188.          */
  189.         switch(uchar(data->data[0])){
  190.         case ICMP_ECHO_REPLY:
  191.         case ICMP_ECHO:
  192.         case ICMP_TIMESTAMP:
  193.         case ICMP_TIME_REPLY:
  194.         case ICMP_INFO_RQST:
  195.         case ICMP_INFO_REPLY:
  196.             break;  /* These are all safe */
  197.         default:
  198.             /* Never send an ICMP error message about another
  199.              * ICMP error message!
  200.              */
  201.             return -1;
  202.         }
  203.     }
  204.     /* Compute amount of original datagram to return.
  205.      * We return the original IP header, and up to 8 bytes past that.
  206.      */
  207.     dlen = min(8,len_p(data));
  208.     length = dlen + ICMPLEN + IPLEN + ip->optlen;
  209.     /* Take excerpt from data portion */
  210.     if(data != NULLBUF && dup_p(&bp,data,0,dlen) == 0)
  211.         return -1;      /* The caller will free data */
  212.  
  213.     /* Recreate and tack on offending IP header */
  214.     if((data = htonip(ip,bp,IP_CS_NEW)) == NULLBUF){
  215.         free_p(bp);
  216.         icmpOutErrors++;
  217.         return -1;
  218.     }
  219.     icmp.type = type;
  220.     icmp.code = code;
  221.     icmp.args.unused = 0;
  222.     switch(uchar(icmp.type)){
  223.     case ICMP_PARAM_PROB:
  224.         icmpOutParmProbs++;
  225.         icmp.args.pointer = args->pointer;
  226.         break;
  227.     case ICMP_REDIRECT:
  228.         icmpOutRedirects++;
  229.         icmp.args.address = args->address;
  230.         break;
  231.     case ICMP_ECHO:
  232.         icmpOutEchos++;
  233.         break;
  234.     case ICMP_ECHO_REPLY:
  235.         icmpOutEchoReps++;
  236.         break;
  237.     case ICMP_INFO_RQST:
  238.         break;
  239.     case ICMP_INFO_REPLY:
  240.         break;
  241.     case ICMP_TIMESTAMP:
  242.         icmpOutTimestamps++;
  243.         break;
  244.     case ICMP_TIME_REPLY:
  245.         icmpOutTimestampReps++;
  246.         icmp.args.echo.id = args->echo.id;
  247.         icmp.args.echo.seq = args->echo.seq;
  248.         break;
  249.     case ICMP_ADDR_MASK:
  250.         icmpOutAddrMasks++;
  251.         break;
  252.     case ICMP_ADDR_MASK_REPLY:
  253.         icmpOutAddrMaskReps++;
  254.         break;
  255.     case ICMP_DEST_UNREACH:
  256.         if(icmp.code == ICMP_FRAG_NEEDED)
  257.             icmp.args.mtu = args->mtu;
  258.         icmpOutDestUnreachs++;
  259.         break;
  260.     case ICMP_TIME_EXCEED:
  261.         icmpOutTimeExcds++;
  262.         break;
  263.     case ICMP_QUENCH:
  264.         icmpOutSrcQuenchs++;
  265.         break;
  266.     }
  267.     
  268.     icmpOutMsgs++;
  269.     /* Now stick on the ICMP header */
  270.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  271.         free_p(data);
  272.         return -1;
  273.     }
  274.     return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  275. }
  276.